package com.hulk.hyena.project.utils;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import de.taimos.totp.TOTP;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base32;
import org.apache.commons.codec.binary.Hex;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.SecureRandom;
import java.util.Scanner;

@Slf4j
public class GoogleAuthenticationUtil {

    private static String secretKey = "QDWSM3OYBPGTEVSPB5FKVDM3CSNCWHVK";

    /**
     * 生成Google authentication 密钥
     * @return
     */
    public static String generateSecretKey() {
        SecureRandom random = new SecureRandom();
        byte[] bytes = new byte[10];
        random.nextBytes(bytes);
        Base32 base32 = new Base32();
        return base32.encodeToString(bytes);
    }

    /**
     * base32 编码的密钥 转成 十六进制表示
     *
     * @param secretKey
     * @return
     */
    public static String getTOTPCode(String secretKey) {
        Base32 base32 = new Base32();
        byte[] bytes = base32.decode(secretKey);
        String hexKey = Hex.encodeHexString(bytes);
        return TOTP.getOTP(hexKey);
    }

    /**
     * generate time-based 6-digits code
     */
    public static void genCode() {
        String lastCode = null;
        while (true) {
            String code = getTOTPCode(secretKey);
            if (!code.equals(lastCode)) {
                log.info(code);
            }
            lastCode = code;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {};
        }
    }

    /**
     *
     * @param secretKey
     * @param account Account is the user id in system
     * @param issuer Issuer is a company or organization name and is also used for labelling purposes
     * @return
     */
    public static String getGoogleAuthenticatorBarCode(String secretKey, String account, String issuer) {
        try {
            return "otpauth://totp/"
                    + URLEncoder.encode(issuer + ":" + account, "UTF-8").replace("+", "%20")
                    + "?secret=" + URLEncoder.encode(secretKey, "UTF-8").replace("+", "%20")
                    + "&issuer=" + URLEncoder.encode(issuer, "UTF-8").replace("+", "%20");
        } catch (UnsupportedEncodingException e) {
            throw new IllegalStateException(e);
        }
    }

    /**
     * 生成二维码
     * @param barCodeData
     * @param filePath
     * @param height
     * @param width
     * @throws WriterException
     * @throws IOException
     */
    public static void createQRCode(String barCodeData, String filePath, int height, int width)
            throws WriterException, IOException {
        BitMatrix matrix = new MultiFormatWriter().encode(barCodeData, BarcodeFormat.QR_CODE,
                width, height);
        try (FileOutputStream out = new FileOutputStream(filePath)) {
            MatrixToImageWriter.writeToStream(matrix, "png", out);
        }
    }

    public static void demo() {
        Scanner scanner = new Scanner(System.in);
        String code = scanner.nextLine();
        if (code.equals(getTOTPCode(secretKey))) {
            System.out.println("Logged in successfully");
        } else {
            System.out.println("Invalid 2FA Code");
        }
    }

    public static void main(String... args) throws Exception {
//        createQRCode(getGoogleAuthenticatorBarCode("2DYMFVCB7RMOEWAK", "admin", "Migo 控制台(测试)"), "qrcode_admin_test.png", 400, 400);
//        createQRCode(getGoogleAuthenticatorBarCode("EXXW5ZXDQZB22QXG", "admin", "Migo 控制台"), "qrcode_admin_pro.png", 400, 400);




//        genCode();

//        demo();
        System.out.println(generateSecretKey());

//        System.out.println(getTOTPCode("RXO3IIDVCXJFYZT7"));
//        for (int i=0; i<50; i++) {
//            log.info(generateSecretKey());
//        }
    }

}
